/*
 * buffer_impl.h
 *
 *  Created on: 2016-4-2
 *      Author: ZhangXiyin
 */

#ifndef EYAS_SOURCES_BUFFER_IMPL_BUFFER_IMPL_H_
#define EYAS_SOURCES_BUFFER_IMPL_BUFFER_IMPL_H_

#include <boost/noncopyable.hpp>
#include "../conf/def.h"
#ifdef WIN32
#include <memory>
#include<winsock2.h>
#else
#include <string.h>
#include <arpa/inet.h>
#endif

namespace eyas {
namespace buffer {

class buffer_impl : public boost::noncopyable{
private:
	// 片大小
	int32_t slice_length;
	//
	bool auto_expend;

	typedef bool write_return;
	const static bool default_write_return = false;
	typedef bool replace_return;
	const static bool default_replace_reaturn = false;
public:
	// 空构造
	buffer_impl()
	:slice_length(1024), auto_expend(true), _buffer(nullptr), _buffer_end(nullptr), _read_buffer(nullptr), _write_buffer(nullptr){
	}
	buffer_impl(int32_t slice_length)
	:slice_length(slice_length), auto_expend(true), _buffer(nullptr), _buffer_end(nullptr), _read_buffer(nullptr), _write_buffer(nullptr){
	}
	buffer_impl(int32_t slice_length, bool auto_expend)
	:slice_length(slice_length), auto_expend(auto_expend), _buffer(nullptr), _buffer_end(nullptr), _read_buffer(nullptr), _write_buffer(nullptr){
	}
	buffer_impl(int32_t slice_length, bool auto_expend, unsigned char* buffer, unsigned length)
	:slice_length(slice_length), auto_expend(auto_expend), _buffer(buffer), _buffer_end(buffer+length), _read_buffer(buffer), _write_buffer(buffer){
	}
	buffer_impl(unsigned char* buffer, unsigned length)
	:slice_length(length), auto_expend(false), _buffer(buffer), _buffer_end(buffer+length), _read_buffer(buffer), _write_buffer(buffer){
	}
	// 移动构造
	buffer_impl(EYAS_BUFFER_RV_REF(buffer_impl) buffer)
	:slice_length(buffer.slice_length), auto_expend(buffer.auto_expend), _buffer(buffer._buffer), _buffer_end(buffer._buffer_end), _read_buffer(buffer._read_buffer), _write_buffer(buffer._write_buffer){
		buffer._buffer = nullptr;
		buffer._buffer_end = nullptr;
		buffer._read_buffer = nullptr;
		buffer._write_buffer = nullptr;
	}
	virtual ~buffer_impl(){
		this->free();
	}
protected:
	unsigned char* _buffer;
	unsigned char* _buffer_end;
	mutable unsigned char* _read_buffer;
	unsigned char* _write_buffer;
protected:
	void free(){
		if(nullptr != _buffer){
			if(auto_expend){
				::free(_buffer);
			}
			_buffer = nullptr;
			_buffer_end = nullptr;
			_read_buffer = nullptr;
			_write_buffer = nullptr;
		}
	}
	// 转交，将内容转交给buffer
	void release(buffer_impl& buffer){
		buffer._buffer = _buffer;
		buffer._buffer_end = _buffer_end;
		buffer._read_buffer = _read_buffer;
		buffer._write_buffer = _write_buffer;

		_buffer = nullptr;
		_buffer_end = nullptr;
		_read_buffer = nullptr;
		_write_buffer = nullptr;
	}
	void set(int32_t slice_length, bool auto_expend, unsigned char* buffer, unsigned length){
		this->free();
		this->slice_length = slice_length;
		this->auto_expend = auto_expend;
		_buffer = buffer;
		_buffer_end = buffer+length;
		_read_buffer = buffer;
		_write_buffer = buffer;
	}
	void set(unsigned char* buffer, unsigned length){
		this->free();
		this->slice_length = length;
		this->auto_expend = false;
		_buffer = buffer;
		_buffer_end = buffer+length;
		_read_buffer = buffer;
		_write_buffer = buffer;
	}
	virtual void init() = 0;
private:
#ifdef EYAS_ENABLE_C11
	// 禁用移动拷贝，须在子类中实现
	buffer_impl& operator=(EYAS_BUFFER_RV_REF(buffer_impl) buffer){
		return *this;
	}
#endif
	// 禁用递交拷贝，须在子类中实现
	buffer_impl& operator=(buffer_impl& buffer){
		return *this;
	}
public:
	// 自动移动数据到缓冲区起始处
	void autoMove(){
		if(nullptr == _buffer){
			return;
		}
		if(_buffer == _read_buffer){
			return;
		}
		memmove(_buffer, _read_buffer, _write_buffer - _read_buffer);
		_write_buffer -= _read_buffer - _buffer;
		_read_buffer = _buffer;
	}
	const unsigned char* get_buffer() const{
		return this->_buffer;
	}
	unsigned char* get_buffer(){
		return this->_buffer;
	}
	unsigned char* get_write_buffer(int32_t length){
		if(auto_expend){
			length -= static_cast<int32_t>(_buffer_end - _write_buffer);
			if(length > 0){
				int32_t needlength = static_cast<int32_t>(length > slice_length ? (length/slice_length+1)*slice_length : slice_length);
				if(needlength - length >= slice_length){
					needlength -= slice_length;
				}
				unsigned char* buf = static_cast<unsigned char*>(nullptr == _buffer ? malloc(needlength) : realloc(_buffer, _buffer_end - _buffer + needlength));
				if(nullptr == buf)
					return nullptr;
				_read_buffer = buf + (_read_buffer - _buffer);
				_write_buffer = buf + (_write_buffer - _buffer);
				_buffer_end = buf + ((_buffer_end - _buffer) + needlength);
				_buffer = buf;
			}
		}else{
			if(nullptr == _buffer){
				this->init();
			}
			if(length > _buffer_end - _write_buffer){
				return nullptr;
			}
		}
		return _write_buffer;
	}
	unsigned char* get_write_buffer(){
		return this->_write_buffer;
	}
	void commit_write(int32_t length){
		_write_buffer += length;
	}
	const unsigned char* get_read_buffer() const{
		return this->_read_buffer;
	}
	void commit_read(int32_t length) const{
		this->_read_buffer += length;
	}
	// 可读取长度
	int32_t length() const{
		return static_cast<int32_t>(_write_buffer - _read_buffer);
	}
	// 已读取数据长度
	int32_t rlength() const{
		return static_cast<int32_t>(_read_buffer - _buffer);
	}
	// 已写入数据长度
	int32_t wlength() const{
		return static_cast<int32_t>(_write_buffer - _buffer);
	}
	int32_t idlelength() const{
		return static_cast<int32_t>(_buffer_end - _write_buffer);
	}
	// 当前缓冲区长度。
	int32_t capacity() const{
		return static_cast<int32_t>(_buffer_end - _buffer);
	}
	void clear(){
		_read_buffer = _buffer;
		_write_buffer = _buffer;
	}
	//explicit
	bool write(const unsigned char* buf, int32_t length){
		if( length <= 0 )
			return true;
		unsigned char* streamData = get_write_buffer(length);
		if(nullptr == streamData){
			return false;
		}
		memcpy(streamData, buf, length);
		this->commit_write(length);
		return true;
	}

#include "buffer_write.hpp"

	bool replace(int32_t offset, const unsigned char* buf, int32_t length){
		if( length <= 0 )
			return true;
		if(_read_buffer + offset + length > _write_buffer){
			return false;
		}
		memcpy(_read_buffer + offset, buf, length);
		return true;
	}
#include "buffer_replace.hpp"


	bool read(unsigned char* buf, int32_t length){
		if(length > _write_buffer - _read_buffer){
			return false;
		}
		memcpy(buf, get_read_buffer(), length);
		commit_read(length);
		return true;
	}
#include "buffer_read.hpp"

	bool detect(int32_t offset, unsigned char* buf, int32_t length){
		if(_read_buffer + (offset+length) > _write_buffer){
			return false;
		}
		memcpy(buf, _read_buffer + offset, length);
		return true;
	}
#include "buffer_detect.hpp"
};

} /* namespace thread */
} /* namespace eyas */
#endif /* EYAS_SOURCES_BUFFER_IMPL_BUFFER_IMPL_H_ */
